﻿using System;

using System.Collections.Generic;
using System.Text;
using System.IO;

namespace gpsmid_wince.util {
	class Legend {
	/**
	 * Specifies the format of the map on disk we expect to see
	 * This constant must be in sync with Osm2GpsMid
	 */
	public const short MAP_FORMAT_VERSION = 54;

	/** The waypoint format used in the RecordStore. See PositionMark.java. */
	public const short WAYPT_FORMAT_VERSION = 2;

	public const sbyte MIN_PLACETYPE = 1; // city
	public const sbyte MAX_PLACETYPE = 5; // suburb

	//public const sbyte NODE_MASK_ROUTENODELINK = 0x1; //obsolete
	public const sbyte NODE_MASK_TYPE = 0x2;
	public const sbyte NODE_MASK_NAME = 0x4;
	public const sbyte NODE_MASK_ROUTENODE = 0x8;
	public const sbyte NODE_MASK_NAMEHIGH = 0x10;

	public const sbyte LEGEND_FLAG_IMAGE = 0x01;
	public const sbyte LEGEND_FLAG_SEARCH_IMAGE = 0x02;
	public const sbyte LEGEND_FLAG_MIN_IMAGE_SCALE = 0x04;
	public const sbyte LEGEND_FLAG_MIN_ONEWAY_ARROW_SCALE = LEGEND_FLAG_MIN_IMAGE_SCALE;
	public const sbyte LEGEND_FLAG_TEXT_COLOR = 0x08;
	public const sbyte LEGEND_FLAG_NON_HIDEABLE = 0x10;
	// public const sbyte LEGEND_FLAG_NON_ROUTABLE = 0x20;
	public const sbyte LEGEND_FLAG_MIN_DESCRIPTION_SCALE = 0x40;

	public const short ROUTE_FLAG_MOTORWAY = 0x01;  // used in ConnectionWithNode AND WayDescription
	public const short ROUTE_FLAG_MOTORWAY_LINK = 0x02; // used in ConnectionWithNode AND WayDescription
	public const short ROUTE_FLAG_ROUNDABOUT = 0x04; // used in ConnectionWithNode
	public const short ROUTE_FLAG_TUNNEL = 0x08; // used in ConnectionWithNode
	public const short ROUTE_FLAG_BRIDGE = 0x10; // used in ConnectionWithNode
	public const short ROUTE_FLAG_INVISIBLE = 0x20; // used in ConnectionWithNode
	public const short ROUTE_FLAG_INCONSISTENT_BEARING = 0x40; // used in ConnectionWithNode
	public const short ROUTE_FLAG_QUIET = 0x80; // used in ConnectionWithNode
	public const short ROUTE_FLAG_LEADS_TO_MULTIPLE_SAME_NAMED_WAYS = 0x100; // used in ConnectionWithNode
	public const short ROUTE_FLAG_BEAR_LEFT = 0x200; // used in ConnectionWithNode
	public const short ROUTE_FLAG_BEAR_RIGHT = 0x400; // used in ConnectionWithNode
	public const short ROUTE_FLAG_ONEDIRECTION_ONLY = 0x800; // used in ConnectionWithNode
	public const short ROUTE_FLAG_AREA = 0x1000; // used in ConnectionWithNode
	public const short ROUTE_FLAG_VERY_SMALL_DISTANCE = 0x2000; // used in ConnectionWithNode

	/**
	 * minimum distances to set the is_in name to the next city
	 * to get the minimum distance use: <code>MAX_DIST_CITY[node.getType(null)]</code>
	 */

	public const sbyte NAME_CITY = 1;
	public const sbyte NAME_SUBURB = 2;
	public const sbyte NAME_STREET = 3;
	public const sbyte NAME_AMENITY = 4;

	public const sbyte OM_HIDE = 0;
	public const sbyte OM_SHOWNORMAL = 1;
	public const sbyte OM_OVERVIEW = 2;
	// OM_OVERVIEW2 is used to set overview mode for the element without setting the checkbox in the UI.
	public const sbyte OM_OVERVIEW2 = 4;
	public const sbyte OM_MODE_MASK = OM_SHOWNORMAL | OM_OVERVIEW | OM_OVERVIEW2;

	public const sbyte OM_NAME_ALL = 0;
	public const sbyte OM_NO_NAME = 8;
	public const sbyte OM_WITH_NAME = 16;
	public const sbyte OM_WITH_NAMEPART = 32;
	public const sbyte OM_NAME_MASK = OM_NO_NAME | OM_WITH_NAME | OM_WITH_NAMEPART;


	public const int COLOR_MAP_BACKGROUND = 0;
	public const int COLOR_MAP_TEXT = 1;
	public const int COLOR_SPEED_BACKGROUND = 2;
	public const int COLOR_SPEED_TEXT = 3;
	public const int COLOR_TITLEBAR_BACKGROUND = 4;
	public const int COLOR_TITLEBAR_TEXT = 5;
	public const int COLOR_WAYNAME_BACKGROUND = 6;
	public const int COLOR_WAYNAME_TEXT = 7;
	public const int COLOR_AREA_LABEL_TEXT = 8;
	public const int COLOR_WAY_LABEL_TEXT = 9;
	public const int COLOR_WAY_LABEL_TEXT_ABBREVIATED = 10;
	public const int COLOR_POI_LABEL_TEXT = 11;
	public const int COLOR_WAYPOINT_TEXT = 12;
	public const int COLOR_ONEWAY_ARROW = 13;
	public const int COLOR_ONEWAY_ARROW_NON_FITTING = 14;
	public const int COLOR_RECORDING_SUSPENDED_TEXT = 15;
	public const int COLOR_RECORDING_ON_TEXT = 16;
	public const int COLOR_CELLID_LOG_ON_TEXT = 17;
	public const int COLOR_CELLID_LOG_ON_ATTEMPTING_TEXT = 18;
	public const int COLOR_AUDIOREC_TEXT = 19;
	public const int COLOR_DEST_TEXT = 20;
	public const int COLOR_DEST_LINE = 21;
	public const int COLOR_MAP_CURSOR = 22;
	public const int COLOR_MAP_POSINDICATOR = 23;
	public const int COLOR_SCALEBAR = 24;
	public const int COLOR_ZOOM_BUTTON = 25;
	public const int COLOR_ZOOM_BUTTON_TEXT = 26;
	public const int COLOR_COMPASS_DIRECTION_BACKGROUND = 27;
	public const int COLOR_COMPASS_DIRECTION_TEXT = 28;
	public const int COLOR_SPEEDING_SIGN_BORDER = 29;
	public const int COLOR_SPEEDING_SIGN_INNER = 30;
	public const int COLOR_SPEEDING_SIGN_TEXT = 31;
	public const int COLOR_RI_AT_DEST = 32;
	public const int COLOR_RI_ON_ROUTE = 33;
	public const int COLOR_RI_OFF_ROUTE_SLIGHT = 34;
	public const int COLOR_RI_OFF_ROUTE_FULL = 35;
	public const int COLOR_RI_NOT_AT_ROUTE_LINE_YET = 36;
	public const int COLOR_RI_CHECK_DIRECTION = 37;
	public const int COLOR_RI_TEXT = 38;
	public const int COLOR_RI_DISTANCE_BACKGROUND = 39;
	public const int COLOR_RI_DISTANCE_TEXT = 40;
	public const int COLOR_RI_ETA_BACKGROUND = 41;
	public const int COLOR_RI_ETA_TEXT = 42;
	public const int COLOR_RI_OFF_DISTANCE_TEXT = 43;
	public const int COLOR_ROUTE_ROUTELINE = 44;
	public const int COLOR_ROUTE_ROUTELINE_BORDER = 45;
	public const int COLOR_ROUTE_PRIOR_ROUTELINE = 46;
	public const int COLOR_ROUTE_PRIOR_ROUTELINE_BORDER = 47;
	public const int COLOR_ROUTE_ROUTEDOT = 48;
	public const int COLOR_ROUTE_ROUTEDOT_BORDER = 49;
	public const int COLOR_ICONMENU_BACKGROUND = 50;
	public const int COLOR_ICONMENU_TABBUTTON_BORDER = 51;
	public const int COLOR_ICONMENU_TABBUTTON_TEXT = 52;
	public const int COLOR_ICONMENU_TABBUTTON_TEXT_HIGHLIGHT = 53;
	public const int COLOR_ICONMENU_TABBUTTON_TEXT_INACTIVE = 54;
	public const int COLOR_ICONMENU_ICON_TEXT = 55;
	public const int COLOR_ICONMENU_ICON_BORDER_HIGHLIGHT = 56;
	public const int COLOR_ALERT_BACKGROUND = 57;
	public const int COLOR_ALERT_BORDER = 58;
	public const int COLOR_ALERT_TITLE_BACKGROUND = 59;
	public const int COLOR_ALERT_TEXT = 60;
	public const int COLOR_CUSTOMMENU_BACKGROUND = 61;
	public const int COLOR_CUSTOMMENU_BORDER = 62;
	public const int COLOR_CUSTOMMENU_TITLE_BACKGROUND = 63;
	public const int COLOR_CUSTOMMENU_TEXT = 64;
	public const int COLOR_CUSTOMMENU_HIGHLIGHT_BACKGROUND = 65;
	public const int COLOR_TACHO_BACKGROUND = 66;
	public const int COLOR_TACHO_TEXT = 67;
	public const int COLOR_CLOCK_BACKGROUND = 68;
	public const int COLOR_CLOCK_TEXT = 69;
	public const int COLOR_BRIDGE_DECORATION = 70;
	public const int COLOR_TUNNEL_DECORATION = 71;
	public const int COLOR_WAY_DAMAGED_BORDER = 72;
	public const int COLOR_WAY_DAMAGED_DECORATION = 73;
	public const int COLOR_DAMAGED_BORDER = 74;
	public const int COLOR_COUNT = 75;

	public static int[] COLORS = new int[COLOR_COUNT];

	public static String[] soundFormats;

	public static String appVersion;
	public static String bundleDate;
	public static bool enableEdits;

	//private static POIdescription[] pois;
	private static WayDescription[] ways;

	private static String[] namePartRequired = new String[3];

	public static int[] tileScaleLevel = { Int32.MaxValue, 900000, 180000, 45000 };

	//private static TravelMode midletTravelModes[];

	private static Logger logger = Logger.getInstance("Legend", Logger.TRACE);

	public Legend() {
		readLegend();

		namePartRequired[0] = "";
		namePartRequired[1] = "";
		namePartRequired[2] = "";
	}

	public static void readLegend() {

		JavaDataInputStream ds = new JavaDataInputStream(File.OpenRead(DictReader.basename+@"/legend.dat") );

		/**
		 * Check to see if we have the right version of the Map format
		 */
		short mapVersion = ds.readShort();
		if (mapVersion != MAP_FORMAT_VERSION) {
			throw new IOException("The Map files are not the version we expected, " +
					"please use the correct Osm2GpsMid to recreate the map " +
					"data.  Expected: " + MAP_FORMAT_VERSION + " Read: " + mapVersion);
		}

		appVersion = ds.readUTF();
		bundleDate = ds.readUTF();
		enableEdits = ds.readBoolean();
		//#if polish.api.osm-editing

		//#else
		if (enableEdits) {
			throw new IOException("The Map files are enabled for editing, but editing is not compiled into GpsMid." +
					"Please use the correct Osm2GpsMid to recreate the map ");
		}
		//#endif

		/*
		 * Read colors
		 */
		int count = (int) ds.readShort();
		if (count != COLOR_COUNT) {
			throw new IOException("Map file contains " + count + "colors but midlet's COLOR_COUNT is " + COLOR_COUNT);
		}
		for (int i = 0; i < COLOR_COUNT; i++) {
			COLORS[i] = readDayOrNightColor(ds);
		}

		/*
		 * Read Tile Scale Levels
		 */
		for (int i = 0; i < 4; i++) {
			tileScaleLevel[i] = ds.readInt();
		}

		/*
		 * Read Travel Modes
		 */
		count = (int) ds.readByte();
		//midletTravelModes = new TravelMode[count];
		for (int i = 0; i < count; i++) {
			ds.readUTF();
			ds.readShort();
			ds.readShort();
			ds.readShort();
			ds.readByte();
		}

		// If we do not have the travel mode stored defined in the record store in the midlet data, use the first one
		/*
		if (Configuration.getTravelModeNr() > Legend.getTravelModes().length-1) {
			Configuration.setTravelMode(0);
		}*/

		readPOIdescriptions(ds);
		readWayDescriptions(ds);

		/*
		 * Read sound formats
		 */
		count = (int) ds.readByte();
		soundFormats = new String[count];
		for (int i = 0; i < count; i++) {
			soundFormats[i] = ds.readUTF();
		}

		ds.close();
	}

	private static void readPOIdescriptions(JavaDataInputStream ds) {
		sbyte numPoiDesc = ds.readByte();
		//#debug info
		logger.info("Reading " + (numPoiDesc - 1) + " POI descriptions (+ 1 bogus) from legend.dat");
		for (int i = 0; i < numPoiDesc; i++) {			
			if (ds.readByte() != i) {
				logger.error("Read legend had trouble reading POI descriptions");
			}
			sbyte flags = ds.readByte();
			ds.readUTF();
			ds.readBoolean();
			ds.readInt();			
			if ((flags & LEGEND_FLAG_IMAGE) > 0) {
				ds.readUTF();				
			}
			if ((flags & LEGEND_FLAG_SEARCH_IMAGE) > 0) {
				ds.readUTF();
				
			}
			if ((flags & LEGEND_FLAG_MIN_IMAGE_SCALE) > 0) {
				ds.readInt();
			} 
			if ((flags & LEGEND_FLAG_TEXT_COLOR) > 0) {
				ds.readInt();
			} 
		}
	}

	private static int readDayOrNightColor(JavaDataInputStream ds) {
		int color = ds.readInt();
		int colorNight = color;
		if ( (color & 0x01000000) > 0) {
			colorNight = ds.readInt();
		}/*
		if (Configuration.getCfgBitState(Configuration.CFGBIT_NIGHT_MODE)) {
			color = colorNight;
		}*/
		return color & 0x00FFFFFF;
	}

	private static void readWayDescriptions(JavaDataInputStream ds) {
		sbyte numWayDesc = ds.readByte();
		//#debug info
		logger.info("Reading " + (numWayDesc - 1) + " way descriptions (+ 1 bogus) from legend.dat");
		ways = new WayDescription[numWayDesc];
		for (int i = 0; i < ways.Length; i++) {
			ways[i] = new WayDescription();
			if (ds.readByte() != i) {
				logger.error("Read legend had trouble reading way descriptions");
			}
			sbyte flags = ds.readByte();
			ways[i].hideable = ((flags & LEGEND_FLAG_NON_HIDEABLE) == 0);
			ways[i].routeFlags = ds.readByte();
			ways[i].description = ds.readUTF();
			ways[i].maxScale = ds.readInt();
			ways[i].maxTextScale = ds.readInt();
			ways[i].isArea = ds.readBoolean();
			ways[i].lineColor = readDayOrNightColor(ds);
			ways[i].boardedColor = readDayOrNightColor(ds);
			ways[i].wayWidth = ds.readByte();
			ways[i].overviewMode = OM_SHOWNORMAL;
			ways[i].wayDescFlags = ds.readInt();
			if ((flags & LEGEND_FLAG_MIN_ONEWAY_ARROW_SCALE) > 0) {
				ways[i].maxOnewayArrowScale = ds.readInt();
			} else {
				ways[i].maxOnewayArrowScale = ways[i].maxScale;
			}
			if ((flags & LEGEND_FLAG_MIN_DESCRIPTION_SCALE) > 0) {
				ways[i].maxDescriptionScale = ds.readInt();
			} else {
				ways[i].maxDescriptionScale = 15000;
			}
			//#if polish.api.osm-editing
			if (enableEdits) {
				int noKVpairs = ds.readShort();
				ways[i].osmTags = new String[noKVpairs * 2];
				for (int j = 0; j < noKVpairs * 2; j++) {
					ways[i].osmTags[j] = ds.readUTF();
				}
			}
			//#endif
		}
	}
/*
	//#if polish.api.osm-editing
	public static String[] getNodeOsmTags(sbyte type) {
		return pois[type].osmTags;
	}
	//#endif

	public static int getNodeTextColor(sbyte type) {
		return pois[type].textColor;
	}

	public static Image getNodeImage(sbyte type)  {
		return pois[type].image;
	}

	public static Image getNodeSearchImage(sbyte type)  {
		return pois[type].searchIcon;
	}

	public static int getNodeMaxScale(sbyte type) {
		return pois[type].maxImageScale;
	}

	public static int getNodeMaxTextScale(sbyte type) {
		return pois[type].maxTextScale;
	}

	public static bool isNodeImageCentered(sbyte type) {
		return pois[type].imageCenteredOnNode;
	}

	public static  bool isNodeHideable(sbyte type) {
		return pois[type].hideable;
	}

	public static  sbyte getNodeOverviewMode(sbyte type) {
		return pois[type].overviewMode;
	}

	public static void setNodeOverviewMode(sbyte type, sbyte state) {
		pois[type].overviewMode = state;
	}

	public static void clearAllNodesOverviewMode() {
		for (sbyte i = 1; i < getMaxType(); i++) {
			pois[i].overviewMode = OM_SHOWNORMAL;
		}
	}
	public static   String getNodeTypeDesc(sbyte type) {
		if (type < 0 || type >= pois.length) {
			logger.error("ERROR: Invalid POI type " + type + " requested!");
			return null;
		}
		return pois[type].description;
	}
*/
	public static  WayDescription getWayDescription(sbyte type) {
		if (type < 0 || type >= ways.Length) {
			logger.error("ERROR: Invalid way type " + type + " requested");
			return null;
 		}
		return ways[type];
	}

	public static  bool isWayHideable(sbyte type) {
		return ways[type].hideable;
	}

	public static sbyte getWayOverviewMode(sbyte type) {
		return ways[type].overviewMode;
	}

	public static void setWayOverviewMode(sbyte type, sbyte state) {
		ways[type].overviewMode = state;
	}

	public static String get0Poi1Area2WayNamePart(sbyte nr) {
		return namePartRequired[nr];
	}

	public static void set0Poi1Area2WayNamePart(sbyte nr, String namePart) {
		namePartRequired[nr] = namePart;
	}

	public static void clearAllWaysOverviewMode() {
		for (sbyte i = 1; i < getMaxWayType(); i++) {
			ways[i].overviewMode = OM_SHOWNORMAL;
		}
	}
/*
	public static TravelMode [] getTravelModes() {
		return midletTravelModes;
	}
*/
	public static  sbyte getMaxWayType() {
		return (sbyte)ways.Length;
	}
/*
	public static  sbyte getMaxType() {
		return (sbyte)pois.length;
	}
*/
	public static sbyte scaleToTile(int scale) {
		if (scale < tileScaleLevel[3]) { 		// 45000 in GpsMid 0.5.0
			return 3;
		} else if (scale < tileScaleLevel[2]) { // 180000 in GpsMid 0.5.0
			return 2;
 		} else if (scale < tileScaleLevel[1]) { // 900000 in GpsMid 0.5.0
			return 1;
		}
		return 0;
	}

	public static String getAppVersion() {
		return appVersion;
	}

	public static String getBundleDate() {
		return bundleDate;
	}


	}
}
